package com.octopus.kernal.ui.builder;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import com.octopus.kernal.dao.BaseDao;
import com.octopus.kernal.dao.GenericHibernateDao;
import com.octopus.kernal.model.BaseStruct;
import com.octopus.kernal.service.BusinessModelService;
import com.octopus.kernal.service.ConfigService;
import com.octopus.kernal.ui.element.BaseElement;
import com.octopus.kernal.ui.element.CheckboxElement;
import com.octopus.kernal.ui.element.SelectElement;
import com.octopus.kernal.util.xml.Action;
import com.octopus.kernal.util.xml.Column;
import com.octopus.kernal.util.xml.ElementDetail;
import com.octopus.kernal.util.xml.Entity;
import com.octopus.kernal.util.xml.Field;

@Service
public class DetailTableBuilder<T extends BaseStruct> {
	
	public static String sp = System.getProperty("line.separator");
	
	@Autowired
	private BusinessModelService businessModelService;
	
	@Autowired
	private BaseDao genericDao;
	
	public String build(HttpServletRequest request, T struct, MessageSource messageSource, boolean readonly){
		return this.build(request, struct, messageSource, readonly, null, null);
	}
	
	public String build(HttpServletRequest request, T struct, MessageSource messageSource, boolean readonly, List<String> readonlyFields, List<String> disabledFields){
		if(readonlyFields == null)
			readonlyFields = new ArrayList<String>();
		String entityName = struct.getClass().getSimpleName();
		entityName = entityName.substring(0, entityName.indexOf("Struct"));
		Entity entity = this.businessModelService.getEntityByName(entityName);
		if(entity == null)
			return "";
		StringBuffer html = new StringBuffer();
		int index = 0;
		// Details
		for(Field field : entity.getFields()){
			if(index % entity.getLayoutDetail() == 0)
				html.append("<tr>" + sp);
			ElementDetail element = field.getElementDetail();
			if(element == null)
				continue;
			if(StringUtils.isBlank(element.getId()))
				element.setId(field.getName());
			if(StringUtils.isBlank(element.getName()))
				element.setName(field.getName());
			// Label
			if((index%entity.getLayoutSearch() + element.getLayoutLabel() + element.getLayoutValue()) > entity.getLayoutSearch()){
				html.append("</tr>" + sp);
				html.append("<tr>" + sp);
				index = 0;
			}
			index += element.getLayoutLabel();
			html.append("<td valign=\"top\"");
			if(element.getLayoutLabel() > 1)
				html.append(" colspan=\"" + element.getLayoutLabel() + "\"");
			html.append(">" + sp);
			String key = "label." + entity.getAlias() + ".field." + field.getName();
			html.append(messageSource.getMessage(key, new Object[] { }, LocaleContextHolder.getLocale()));
			if(field.getRequired() && !readonly && !readonlyFields.contains(field.getName()))
				html.append("<font color=\"red\">*</font>");
			html.append(":" + sp);
			html.append("</td>" + sp);
			// Value
			index += element.getLayoutValue();
			html.append("<td");
			if(element.getLayoutValue() > 1)
				html.append(" colspan=\"" + element.getLayoutValue() + "\"");
			html.append(">" + sp);
			try {
				html.append(this.getHtmlElementString(request, field, struct, (readonly || readonlyFields.contains(field.getName())), 
						null==disabledFields?null:disabledFields.contains(field.getName()), messageSource));
			} catch (Exception e) {
				e.printStackTrace();
			}
			html.append("</td>" + sp);
			if(index % entity.getLayoutDetail() == 0)
				html.append("</tr>" + sp);
		}
		if(html.lastIndexOf("</tr>") != html.length() - 5){
			html.append("</tr>");
		}
		return html.toString();
	}
	
	public String buildButton(HttpServletRequest request, T struct, MessageSource messageSource, boolean readonly){
		return buildButton(request, struct, messageSource, readonly, true);
	}
	
	public String buildButton(HttpServletRequest request, T struct, MessageSource messageSource, boolean readonly, boolean actions){
		String entityName = struct.getClass().getSimpleName();
		entityName = entityName.substring(0, entityName.indexOf("Struct"));
		Entity entity = this.businessModelService.getEntityByName(entityName);
		StringBuffer html = new StringBuffer();
		html.append("<tr height=\"50px\"><td align=\"center\" valign=\"bottom\" colspan=\"" + entity.getLayoutDetail() + "\">");
		if(!readonly){
			if(entity.getActions() != null){
				for(Action action : entity.getActions()){
					if(!action.getPost())
						continue;
					String label = "label.common.action." + action.getKey();
					if(action.getCustomized()){
						label = "label." + entity.getAlias() + ".action." + action.getKey();
					}
					if((action.getPermission()==null?true:(SecurityUtils.getSubject().isPermittedAll(action.getPermission().split(",")))) 
							&& action.getShowButton()
							&& businessModelService.isActionAllowed(struct, action.getRule())){
						String confirm = action.getConfirm()?messageSource.getMessage("label.common.confirm." + action.getKey() + "", new Object[] { }, LocaleContextHolder.getLocale()):"";
						html.append("<input type=\"button\" onclick=\"onActionPost('" + action.getKey() + "','" + confirm + "')\" " +
								"value=\"" + messageSource.getMessage(label + "", new Object[] { }, LocaleContextHolder.getLocale()) + "\" >");
						html.append("&nbsp;&nbsp;");
					}
				}
			}	
		}else{
			if(actions && entity.getActions() != null){
				for(Action action : entity.getActions()){
					if(action.getPost())
						continue;
					String url = action.getKey();
					String label = "label.common.action." + action.getKey();
					if(action.getCustomized()){
						url = "x/" + url;
						label = "label." + entity.getAlias() + ".action." + action.getKey();
					}
					if(SecurityUtils.getSubject().isPermitted(entity.getAlias() + ":" + action.getKey()) 
							&& action.getShowButton() 
							&& businessModelService.isActionAllowed(struct, action.getRule())){
						String module = action.getCustomized()?entity.getAlias():"common";
						String confirm = action.getConfirm()?messageSource.getMessage("label." + module + ".confirm." + action.getKey() + "", new Object[] { }, LocaleContextHolder.getLocale()):"";
						html.append("<input type=\"button\" onclick=\"onActionGet('" + url + "', '" + struct.getId() + "','" + confirm + "')\" " +
								"value=\"" + messageSource.getMessage(label + "", new Object[] { }, LocaleContextHolder.getLocale()) + "\" >");
						html.append("&nbsp;&nbsp;");
					}
				}
			}	
		}
		html.append("<input type=\"button\" onclick=\"onCancel()\" value=\"" + messageSource.getMessage("label.common.cancel", new Object[] { }, LocaleContextHolder.getLocale()) + "\"/>");
		html.append("</td></tr>");
		return html.toString();
	}
	
	private String getHtmlElementString(HttpServletRequest request, Field field, T struct, Boolean readonly, Boolean disabled, MessageSource messageSource) throws Exception{
		ElementDetail element = field.getElementDetail();
		Column column = field.getColumn();
		Object value = struct.getAttributeValues().get(field.getName());
		if(element == null)
			return "";
		BaseElement htmlElement = null;
		// Input text
		if(element.getInputElement() != null){
			htmlElement = element.getInputElement();
			htmlElement.setValue(value);
		// Input date
		}else if(element.getDateElement() != null){
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", new Locale("en"));
			htmlElement = element.getDateElement();
			htmlElement.setValue(null==value?null:format.format(value));
		// Input time
		}else if(element.getTimeElement() != null){
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm", new Locale("en"));
			htmlElement = element.getTimeElement();
			htmlElement.setValue(null==value?null:format.format(value));
		// Textarea text
		}else if(element.getTextareaElement() != null){
			htmlElement = element.getTextareaElement();
			htmlElement.setValue(value);
		// Checkbox
		}else if(element.getCheckboxElement() != null){
			CheckboxElement checkboxElement = element.getCheckboxElement();
			checkboxElement.setMessageSource(messageSource);
			htmlElement = checkboxElement;
			if("String".equals(column.getType())){
				
			}else if("Integer".equals(column.getType())){
				
			}else if("Boolean".equals(column.getType())){
				
			}else if("Date".equals(column.getType()) || "Time".equals(column.getType())){
				
			}else{
				if(checkboxElement.getList() && !readonly){
					Class<BaseStruct> refer = this.businessModelService.getReferenceStruct(struct, field.getName());
					GenericHibernateDao<BaseStruct, Long> dao = new GenericHibernateDao<BaseStruct, Long>(refer);
					dao.setSessionFactory(genericDao.getSessionFactory());
					Entity entity = businessModelService.getEntityByClass(refer);
					String[] propertyNames = null;
					if(entity.getDefaultSort() != null){
						propertyNames = new String[]{entity.getDefaultSort()};
					}
					List<BaseStruct> list = dao.findEqualByEntity(null, propertyNames);
					List<Object> list2 = new ArrayList<Object>();
					if(list != null){
						for(BaseStruct s : list)
							list2.add(s);
					}
					checkboxElement.setEntitiesScrope(list2);
				}
			}
			
			htmlElement.setValue(value);
		// Single select
		}else if(element.getSelectElement() != null){
			SelectElement selectElement = element.getSelectElement();
			selectElement.setMessageSource(messageSource);
			htmlElement = selectElement;
			if("String".equals(column.getType())){
				if(!readonly){
					String[] scopes = null;
					if(selectElement.getLabelProperty() != null)
						scopes = ConfigService.getInstance().getProperties("common.single.select." + selectElement.getLabelProperty());
					if(scopes != null && scopes.length > 0){
						selectElement.setEntitiesScrope(new ArrayList<Object>());
						for(String entity : scopes)
							selectElement.getEntitiesScrope().add(entity);
					}
				}
			}else if("Integer".equals(column.getType()) || "Long".equals(column.getType())){
				if(!readonly){
					String[] scopes = null;
					if(selectElement.getLabelProperty() != null)
						scopes = ConfigService.getInstance().getProperties("common.single.select." + selectElement.getLabelProperty());
					if(scopes != null && scopes.length > 0){
						selectElement.setEntitiesScrope(new ArrayList<Object>());
						for(String entity : scopes)
							selectElement.getEntitiesScrope().add(Integer.valueOf(entity));
					}
				}
			}else if("Boolean".equals(column.getType())){
				
			}else if("Date".equals(column.getType()) || "Time".equals(column.getType())){
				
			}else{
				List<Object> list2 = new ArrayList<Object>();
				if(StringUtils.isBlank(selectElement.getScope())){
					Class<BaseStruct> refer = this.businessModelService.getReferenceStruct(struct, field.getName());
					GenericHibernateDao<BaseStruct, Long> dao = new GenericHibernateDao<BaseStruct, Long>(refer);
					dao.setSessionFactory(genericDao.getSessionFactory());
					Entity entity = businessModelService.getEntityByClass(refer);
					String[] propertyNames = null;
					if(entity.getDefaultSort() != null){
						propertyNames = new String[]{entity.getDefaultSort()};
					}
					List<BaseStruct> list = dao.findEqualByEntity(null, propertyNames);
					if(list != null){
						for(BaseStruct s : list)
							list2.add(s);
					}
				}else{
					list2 = this.businessModelService.getScope(selectElement.getScope());
				}
				selectElement.setEntitiesScrope(list2);
			}
			htmlElement.setValue(value);
		}
		if(htmlElement != null){
			htmlElement.setRequest(request);
			htmlElement.setReadonly(readonly);
			if(disabled != null)
				htmlElement.setDisabled(htmlElement.getDisabled() || disabled);
			return htmlElement.toString();
		}
		return "";
	}

}
